package bootstrap

import (
	"bytes"
	"encoding/json"
	"github.com/gin-gonic/gin"
	"gopkg.in/gcfg.v1"
	"io/ioutil"
	"reflect"
	"runtime"
	"store/bootstrap/global"
	"store/libs/helper"
	"store/libs/validator"
	"strings"
)

//全局公开变量成员
var (
	Config *global.Config
)

//全局私有成员变量
var (
	router *gin.Engine
)

/**
 * 启动路由
 */
func Start() *gin.Engine {
	//读取环境变量GIN_MODE的值确定读取的配置文件，如果没有配置，默认读取debug
	configFileName := "config/" + gin.Mode() + ".json"
	//加载配置文件
	err := loadConfig(configFileName)
	if err != nil {
		panic(err.Error())
	}

	ginMode := gin.Mode()
	if Config.Application.GinMode != "" {
		ginMode = Config.Application.GinMode
	}
	//设置运行模式，以配置文件为准
	gin.SetMode(ginMode)

	runtime.GOMAXPROCS(Config.Application.MaxCpu)

	//创建路由
	router = gin.New()

	//加载自定义验证器
	validator.Start()

	return router
}

/**
 * 加载配置文件
 */
func loadConfig(fileName string) error {
	err := gcfg.ReadFileInto(&Config, fileName)

	configBytes, err := ioutil.ReadFile(fileName)
	if err != nil {
		return err
	}

	err = json.Unmarshal(configBytes, &Config)
	if err != nil {
		return err
	}

	return nil
}

func IsDebug() bool {
	return Config.Application.GinMode == "debug"
}

func IsProduct() bool {
	return Config.Application.GinMode == "release"
}

//region 1.1 Param
func ParamInt(key string) int64 {
	val, ok := Config.Params[key]
	if !ok {
		return 0
	}

	return helper.ToInt(val)
}

func ParamBool(key string) bool {
	val, ok := Config.Params[key]
	if !ok {
		return false
	}
	return helper.ToBool(helper.ToString(val))
}

func ParamString(key string) string {
	val, ok := Config.Params[key]
	if !ok {
		return ""
	}
	return helper.ToString(val)
}

//endregion

//region 1.2 Route
func AutoRegisterRoute(routerGroup *gin.RouterGroup, controllerList []interface{}) {
	for _, controller := range controllerList {
		item := reflect.ValueOf(controller)
		//获取控制器路由
		controllerName := item.Type().String()
		nameStart := strings.LastIndex(item.Type().String(), ".")
		if nameStart > -1 {
			controllerName = helper.BigCase2Line(controllerName[nameStart+1:], "-")
		}

		//遍历method
		methodNums := item.NumMethod()
		for index := 0; index < methodNums; index++ {
			//类型判断
			handler, ok := item.Method(index).Interface().(func(*gin.Context))
			if !ok {
				continue
			}

			methodName := helper.BigCase2Line(item.Type().Method(index).Name, "-")

			buf := bytes.NewBufferString("/")
			buf.WriteString(controllerName)

			switch strings.Split(methodName, "-")[0] {
			case "get":
				if len(methodName) > 3 {
					helper.Write2Buffer(buf, "/", methodName[4:])
				}
				routerGroup.GET(buf.String(), handler)
			case "post":
				if len(methodName) > 4 {
					helper.Write2Buffer(buf, "/", methodName[5:])
				}
				routerGroup.POST(buf.String(), handler)
			case "put":
				if len(methodName) > 3 {
					helper.Write2Buffer(buf, "/", methodName[4:])
				}
				routerGroup.PUT(buf.String(), handler)
			case "delete":
				if len(methodName) > 6 {
					helper.Write2Buffer(buf, "/", methodName[7:])
				}
				routerGroup.DELETE(buf.String(), handler)
			case "patch":
				if len(methodName) > 5 {
					helper.Write2Buffer(buf, "/", methodName[6:])
				}
				routerGroup.PATCH(buf.String(), handler)
			case "options":
				if len(methodName) > 7 {
					helper.Write2Buffer(buf, "/", methodName[8:])
				}
				routerGroup.OPTIONS(buf.String(), handler)
			case "head":
				if len(methodName) > 4 {
					helper.Write2Buffer(buf, "/", methodName[5:])
				}
				routerGroup.HEAD(buf.String(), handler)
			default:
				routerGroup.POST(helper.Write2Buffer(buf, "/", methodName).String(), handler)
			}
		}
	}
}

//endregion
